﻿
package extremefx.i18n {
	import XML;
	import flash.utils.Dictionary;	

	/**
	 * @author Marcelo Volmaro
	 */
	public final class Resources {
		private const _INVARIANT:String="invariant";
		private static var _inst:Resources;
		
		private var _res:Object;
		
		private var _defLang:String;
		private var _defCountry:String;
		private var _qeue:Dictionary;
		
		public function Resources(pRes:PrivateClass) {
			_res = {};
			_defLang = "en";
			_defCountry = _INVARIANT;
			_qeue = new Dictionary();
		}

		private static function get _instance():Resources{
			if (_inst == null){
				_inst = new Resources(new PrivateClass());
			}
			
			return _inst;
		}
		
		/**
		 * Gets a resource from the resource bag by its ID
		 * Uses the current culture if no language/country is passed as arguments
		 * @param pName ID of the element to fetch from the resource bag
		 * @param pNumOrCult 	If a number is passed, and the resource contains a formatNumberChoice string, returns the correct string format for the specified number.
		 * 						If an instance of Culture is passed, it is used to get the language resource, or nothing to use the Current Culture info
		 * @param pCult Culture to get the language resource, or nothing to use the Current Culture info
		 * @return The localized text
		 * @throws Error 	if the ID doesn't exists in the resources for every possible combination of Languages/Country pairs
		 * 					(user lang/user country > user lang/invariant > default lang/default country > default lang/invariant)
		 */

		public static function get(pName:String, pNumOrCult:Object = null, pCult:Culture = null):Object {
			var c:Culture;
			
			if (pNumOrCult is Culture){
				c = Culture(pNumOrCult);
				
			} else if (pCult is Culture){
				c = pCult;
				
			} else {
				c = Culture.currentCulture;
			}
			
			var o:Object = _instance._getResource(pName, c.twoLetterISOLanguageName.toLowerCase(), c.twoLetterISOCountryName.toLowerCase());
			if (pNumOrCult is Number){
				var s:String = String(o);
				if (s.indexOf("[I18N]|") == 0) return c.formatNumberChoice(s, uint(pNumOrCult)); 				
			}
			
			return o;
		}
		
		private function _getResource(pName:String, pLang:String, pCountry:String):Object {
			var res:Object = _res;			
			if (res[pLang] && res[pLang][pCountry] && res[pLang][pCountry][pName]){
				return res[pLang][pCountry][pName];
			}
			
			if (pCountry == _INVARIANT){
				if (pLang == _defLang){
					throw new Error("The specified resource ["+pName+"] doesn't exist");			
					return "";
				}
				
				if (pCountry == _defCountry){
					return _getResource(pName, _defLang, _INVARIANT);
				}
				
				return _getResource(pName, _defLang, _defCountry);
			}
			
			return _getResource(pName, pLang, _INVARIANT);
		}
		
		public static function add(pRes:XML):void {
			_instance._parseResource(pRes);
		}
		
		private function _parseResource(pRes:XML):void {
			var nodes:XMLList = pRes.descendants("trans-unit");
			var xmlLang:XMLList = pRes.file.attribute("source-language");
			
			if (xmlLang.length() != 1) {
				throw new Error("No Language defined in XLIFF file");
				return;
			}
			
			var tmp:Array = _getPair(xmlLang[0]);
			var lang:String = tmp[0];
			var country:String = tmp[1];
			
			if(_res[lang] == null) _res[lang] = {};
			if(_res[lang][country] == null) _res[lang][country] = {};
			
			var targets:XMLList;
			
			for each(var transunit:XML in nodes){
				targets = transunit.elements("target");
				
				if (targets.length() == 0){
					targets = transunit.elements("source");
					if (targets.length() == 0) {
						throw new Error("trans-unit must has at least one source or target");
					}
				}
				
				_res[lang][country][transunit.@id] = targets[0].toString();
			}
			
		}

		public static function get defaultLanguage():String {
			return _instance._getDefLang();
		}
		
		private function _getDefLang():String{
			return _defLang + (_defCountry == _INVARIANT ? "" : "-"+_defCountry);
		}
		
		public static function set defaultLanguage(pDefLang:String):void {
			if (pDefLang.length != 2 && pDefLang.length != 5) {
				throw new Error("Invalid language specified as default one");
				return; 
			}
			
			_instance._setDefLang(pDefLang);
		}
		
		private function _setDefLang(pDefLang:String):void{
			var tmp:Array = _getPair(pDefLang);
			_defLang = tmp[0];
			_defCountry = tmp[1];
		}
		
		private function _getPair(pVal:String):Array {
			var lang:String = pVal;
			var country:String = _INVARIANT;
			
			if (lang.indexOf("-") != -1){
				var tmp:Array = lang.split("-");
				lang = tmp[0];				
				country = tmp[1].toLowerCase();				
			}
			
			lang = lang.toLowerCase();
			
			return [lang, country];
		}
	}
}

final class PrivateClass {}